package com.ssy.lingxi.member.merchant.serviceimpl.web;

import com.alibaba.fastjson.JSONObject;
import com.ssy.lingxi.common.constant.basic.EnableDisableStatus;
import com.ssy.lingxi.common.constant.basic.UserLoginSourceEnum;
import com.ssy.lingxi.common.exception.BusinessException;
import com.ssy.lingxi.common.model.dto.UserLoginCacheDTO;
import com.ssy.lingxi.common.response.ResponseCode;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.common.utils.Aes128Util;
import com.ssy.lingxi.common.utils.DateUtil;
import com.ssy.lingxi.common.utils.PasswordUtil;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.member.merchant.api.constant.BaiDuConfigEnum;
import com.ssy.lingxi.member.merchant.config.ServiceConfig;
import com.ssy.lingxi.member.merchant.config.ServiceVariable;
import com.ssy.lingxi.member.merchant.entity.MemberAuthTypeConfigDO;
import com.ssy.lingxi.member.merchant.entity.MemberDO;
import com.ssy.lingxi.member.merchant.entity.MemberUserDO;
import com.ssy.lingxi.member.merchant.api.constant.MemberRelationTypeEnum;
import com.ssy.lingxi.member.merchant.model.constant.MemberUserAuthTypeEnum;
import com.ssy.lingxi.member.merchant.model.vo.basic.request.*;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdateEmailVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdatePasswordVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdatePayPasswordVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.request.UserUpdatePhoneVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.UserAccountAuthQueryVO;
import com.ssy.lingxi.member.merchant.model.vo.maintenance.response.UserAccountSecurityQueryVO;
import com.ssy.lingxi.member.merchant.repository.MemberRepository;
import com.ssy.lingxi.member.merchant.repository.MemberUserRepository;
import com.ssy.lingxi.member.merchant.service.base.IBaseMemberCacheService;
import com.ssy.lingxi.member.merchant.service.feign.IMemberAuthTypeConfigFeignService;
import com.ssy.lingxi.member.merchant.service.feign.ISmsFeignService;
import com.ssy.lingxi.member.merchant.service.web.IMemberAccountSecurityService;
import com.ssy.lingxi.member.merchant.utils.MailUtil;
import com.ssy.lingxi.member.merchant.utils.NameUtils;
import com.ssy.lingxi.member.merchant.utils.SecurityStringUtils;
import com.ssy.lingxi.member.merchant.utils.baidu.AuthUtil;
import com.ssy.lingxi.member.merchant.utils.baidu.IdCardUtil;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.persistence.criteria.Predicate;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


/**
 * 用户账号安全接口实现类
 *
 * @author 万宁
 * @version 2.0.0
 * @date 2020-07-06
 */
@Service
public class MemberAccountSecurityServiceImpl implements IMemberAccountSecurityService {
    @Resource
    private MemberUserRepository memberUserRepository;

    @Resource
    private MemberRepository memberRepository;

    @Resource
    private IBaseMemberCacheService memberCacheService;

    @Resource
    private ISmsFeignService smsFeignService;

    @Resource
    private AuthUtil authUtil;

    @Resource
    private IRedisStringUtils redisStringUtils;
    @Resource
    private IMemberAuthTypeConfigFeignService memberAuthTypeConfigFeignService;

    /**
     * “账户安全”页面，查询用户的手机号码和邮箱，以掩码方式返回
     *
     * @param headers Http头部信息
     * @return 操作结果
     */
    @Override
    public Wrapper<UserAccountSecurityQueryVO> getPhoneAndEmail(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        UserAccountSecurityQueryVO queryVO = new UserAccountSecurityQueryVO();
        queryVO.setUserId(userDO.getId());
        queryVO.setPhone(SecurityStringUtils.getMaskPhone(userDO.getCountryCode(), userDO.getPhone()));
        queryVO.setEmail(SecurityStringUtils.getMaskMail(userDO.getEmail()));
        queryVO.setHasPayPassword(StringUtils.hasLength(memberDO.getPayPassword()) ? EnableDisableStatus.ENABLE.getCode() : EnableDisableStatus.DISABLE.getCode());
        queryVO.setIsAuth(userDO.getIsAuth());
        int i = 0;
        if (StringUtils.hasLength(memberDO.getPayPassword())) {
            i++;
        }

        if (StringUtils.hasLength(userDO.getEmail())) {
            i++;
        }

        if (StringUtils.hasLength(userDO.getPhone())) {
            i++;
        }

        if (StringUtils.hasLength(userDO.getPassword())) {
            i++;
        }

        queryVO.setRate(i * 25);

        return Wrapper.success(queryVO);
    }

    /**
     * （通用）检查支付密码是否正确
     *
     * @param headers       Http头部信息
     * @param payPasswordVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkPayPassword(HttpHeaders headers, PayPasswordVO payPasswordVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(memberDO.getPayPassword())) {
            return Wrapper.fail(ResponseCode.MC_MS_PAY_PASSWORD_NOT_SET);
        }

        if (!PasswordUtil.instance().checkPassword(memberDO.getPayPassword(), payPasswordVO.getPayPassword())) {
            return Wrapper.fail(ResponseCode.MC_MS_PAY_PASSWORD_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改登录密码（手机校验码验证）时，发送手机短信验证码
     *
     * @param headers Http头部信息
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePasswordSmsCode(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();

        String cacheKey = ServiceConfig.CHANGE_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        //发送短信
        return smsFeignService.sendChangePasswordSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改登录密码（手机校验码验证）时，检查手机短信验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkChangePasswordSmsCode(HttpHeaders headers, SmsCodeVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改登录密码（邮箱验证）时，发送邮件验证码
     *
     * @param headers Http头部信息
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendChangePasswordEmailCode(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PASSWORD_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));


        String title = "瓴犀B2B平台";
        String content = "【B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, userDO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改登录密码（邮箱验证）时，检查邮件验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> checkChangePasswordEmailCode(HttpHeaders headers, SmsCodeVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PASSWORD_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改登录密码
     *
     * @param headers      Http头部信息
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> changePassword(HttpHeaders headers, UserUpdatePasswordVO userManageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String newPassword;
        try {
            newPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(userManageVO.getPassword()));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.BUSINESS_ERROR);
        }

        userDO.setPassword(newPassword);
        memberUserRepository.saveAndFlush(userDO);

        //更改会员的密码
        if (userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            memberDO.setPassword(newPassword);
            memberRepository.saveAndFlush(memberDO);
        }

        return Wrapper.success();
    }

    /**
     * 修改邮箱（手机校验码验证）时，发送手机短信验证码
     *
     * @param headers Http头部信息
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangeEmailSmsCode(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_EMAIL_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangeEmailSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改邮箱（手机校验码验证）时，检查手机短信验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 验证结果
     */
    @Override
    public Wrapper<Void> checkChangeEmailSmsCode(HttpHeaders headers, SmsCodeVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_EMAIL_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改邮箱（邮箱验证）时，发送邮件验证码
     *
     * @param headers Http头部信息
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendChangeEmailEmailCode(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));

        String title = "瓴犀B2B平台";
        String content = "【瓴犀B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, userDO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改邮箱（邮箱验证）时，检查邮件验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> checkChangeEmailEmailCode(HttpHeaders headers, SmsCodeVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改邮箱时，向新邮箱发送邮件验证码
     *
     * @param headers Http头部信息
     * @param emailVO 接口参数
     * @return 发送结果
     */
    @Override
    public Wrapper<Void> sendChangeEmailEmailCodeToNew(HttpHeaders headers, EmailVO emailVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            list.add(criteriaBuilder.equal(root.get("email").as(String.class), emailVO.getEmail().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if (memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));

        String title = "瓴犀B2B平台";
        String content = "【瓴犀B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, emailVO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改邮箱
     *
     * @param headers      Http头部信息
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> changeEmail(HttpHeaders headers, UserUpdateEmailVO userManageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String cacheKey = ServiceConfig.CHANGE_EMAIL_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!userManageVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (loginUser.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            } else {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            }

            list.add(criteriaBuilder.equal(root.get("email").as(String.class), userManageVO.getEmail().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if (memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_EXISTS);
        }

        userDO.setEmail(userManageVO.getEmail());
        memberUserRepository.saveAndFlush(userDO);

        //更改会员的邮箱
        if (userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            memberDO.setEmail(userManageVO.getEmail());
            memberRepository.saveAndFlush(memberDO);
        }

        //删除缓存
        memberCacheService.deleteString(cacheKey);

        return Wrapper.success();
    }

    /**
     * 修改手机号码（手机校验码验证）时，发送手机短信验证码
     *
     * @param headers Http头部信息
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePhoneSmsCode(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangePhoneSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改手机号码（手机校验码验证）时，检查手机短信验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkPhoneSmsCode(HttpHeaders headers, SmsCodeVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改手机号码（邮箱验证）时，发送邮件验证码
     *
     * @param headers Http头部信息
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePhoneEmailCode(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PHONE_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.MAILCODE_CACHED_TIME_MINUTES * 60));

        String title = "瓴犀B2B平台";
        String content = "【瓴犀B2B平台】" + smsCode + "，B2B平台动态验证码。工作人员不会向你索要，请勿向任何人泄露。";
        MailUtil.sendTextMail(title, content, userDO.getEmail());

        return Wrapper.success();
    }

    /**
     * 修改手机号码（邮箱验证）时，检查邮件验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkChangePhoneEmailCode(HttpHeaders headers, SmsCodeVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getEmail())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_EMAIL_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PHONE_MAIL_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改手机号码时，向新手机号码发送短信验证码
     *
     * @param headers Http头部信息
     * @param phoneVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePhoneSmsCodeToNew(HttpHeaders headers, PhoneVO phoneVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (loginUser.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            } else {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            }

            list.add(criteriaBuilder.equal(root.get("phone").as(String.class), phoneVO.getPhone().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if (memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId() + ":" + phoneVO.getPhone();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangePhoneSms(phoneVO.getCountryCode(), phoneVO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 修改手机号码时，检查向新手机号码发送的短信验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkNewPhoneSmsCode(HttpHeaders headers, PhoneSmsVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + loginUser.getUserId() + ":" + smsCodeVO.getPhone();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 修改手机号
     *
     * @param headers      Http头部信息
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Transactional(rollbackFor = BusinessException.class)
    @Override
    public Wrapper<Void> changePhone(HttpHeaders headers, UserUpdatePhoneVO userManageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String cacheKey = ServiceConfig.CHANGE_PHONE_SMS_CODE_REDIS_KEY_PREFIX + loginUser.getUserId() + ":" + userManageVO.getPhone();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!userManageVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        //查询手机号码是否已经存在
        Specification<MemberUserDO> specification = (Specification<MemberUserDO>) (root, query, criteriaBuilder) -> {
            List<Predicate> list = new ArrayList<>();
            if (loginUser.getLoginSource().equals(UserLoginSourceEnum.BUSINESS_MANAGEMENT_PLATFORM.getCode())) {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.PLATFORM.getCode()));
            } else {
                list.add(criteriaBuilder.equal(root.get("relType").as(Integer.class), MemberRelationTypeEnum.OTHER.getCode()));
            }

            list.add(criteriaBuilder.equal(root.get("phone").as(String.class), userManageVO.getPhone().trim()));
            list.add(criteriaBuilder.notEqual(root.get("id").as(Long.class), userDO.getId()));
            Predicate[] p = new Predicate[list.size()];
            return criteriaBuilder.and(list.toArray(p));
        };

        if (memberUserRepository.count(specification) > 0) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_EXISTS);
        }

        userDO.setPhone(userManageVO.getPhone());
        //如果是会员的管理员用户：
        //账号就是手机号，所以要更新两个字段
        //会员的账号也是手机号
        if (userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            userDO.setAccount(userManageVO.getPhone());

            memberDO.setAccount(userManageVO.getPhone());
            memberDO.setPhone(userManageVO.getPhone());
            memberRepository.saveAndFlush(memberDO);
        }

        memberUserRepository.saveAndFlush(userDO);

        //删除缓存
        memberCacheService.deleteString(cacheKey);

        return Wrapper.success();
    }

    /**
     * 重置支付密码时，发送手机短信验证码
     *
     * @param headers Http头部信息
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> sendChangePayPswSmsCode(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String smsCode = SecurityStringUtils.getRandomSmsCode();
        String cacheKey = ServiceConfig.CHANGE_PAY_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        memberCacheService.setString(cacheKey, smsCode, (long) (ServiceVariable.SMSCODE_CACHED_TIME_MINUTES * 60));

        return smsFeignService.sendChangePayPasswordSms(userDO.getCountryCode(), userDO.getPhone(), smsCode, ServiceVariable.SMSCODE_CACHED_TIME_MINUTES);
    }

    /**
     * 重置支付密码时，检查手机短信验证码是否正确
     *
     * @param headers   Http头部信息
     * @param smsCodeVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> checkChangePayPswSmsCode(HttpHeaders headers, SmsCodeVO smsCodeVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        if (!StringUtils.hasLength(userDO.getPhone())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_PHONE_DOES_NOT_REGISTER);
        }

        String cacheKey = ServiceConfig.CHANGE_PAY_PASSWORD_SMS_CODE_REDIS_KEY_PREFIX + userDO.getId();
        String smsCode = memberCacheService.getString(cacheKey);
        if (!StringUtils.hasLength(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_EXPIRED);
        }

        if (!smsCodeVO.getSmsCode().equals(smsCode)) {
            return Wrapper.fail(ResponseCode.USER_SMSCODE_INCORRECT);
        }

        return Wrapper.success();
    }

    /**
     * 手机校验码验证后，修改支付密码
     *
     * @param headers      Http头部信息
     * @param userManageVO 接口参数
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> changePayPassword(HttpHeaders headers, UserUpdatePayPasswordVO userManageVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if (memberDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        String encryptPayPassword;
        try {
            encryptPayPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(userManageVO.getPayPassword()));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.SERVICE_ERROR);
        }

        memberDO.setPayPassword(encryptPayPassword);
        memberRepository.saveAndFlush(memberDO);

        return Wrapper.success();
    }

    /**
     * 平台后台 - 更改用户密码
     *
     * @param headers    Http头部信息
     * @param passwordVO 接口参数
     * @return 修改结果
     */
    @Override
    public Wrapper<Void> updatePlatformUserPassword(HttpHeaders headers, PlatformUpdatePasswordVO passwordVO) {
        UserLoginCacheDTO loginUser = memberCacheService.needLoginFromManagePlatform(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }

        MemberDO memberDO = userDO.getMember();
        if (memberDO == null || !memberDO.getId().equals(loginUser.getMemberId())) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_DOES_NOT_EXIST);
        }

        if (!PasswordUtil.instance().checkPassword(userDO.getPassword(), passwordVO.getOldPassword())) {
            return Wrapper.fail(ResponseCode.MC_MS_OLD_PASSWORD_INCORRECT);
        }

        String newPassword;
        try {
            newPassword = PasswordUtil.instance().passwordToMd5String(Aes128Util.aesDecrypt(passwordVO.getNewPassword()));
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.AES_DECRYPTION_ERROR);
        }

        userDO.setPassword(newPassword);
        memberUserRepository.saveAndFlush(userDO);

        //更改会员的密码
        if (userDO.getTypeEnum().equals(MemberUserAuthTypeEnum.ADMIN.getCode())) {
            memberDO.setPassword(newPassword);
            memberRepository.saveAndFlush(memberDO);
        }

        return Wrapper.success();
    }

    /**
     * 账户安全-实名验证-显示已实名认证的信息列表
     *
     * @param headers Http头部信息
     * @return 操作结果
     */
    @Override
    public Wrapper<UserAccountAuthQueryVO> getUserInfo(HttpHeaders headers) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDOPage = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDOPage != null) {
            UserAccountAuthQueryVO vo = new UserAccountAuthQueryVO();
            vo.setUserId(userDOPage.getId());
            //名称脱敏
            vo.setName(NameUtils.process(userDOPage.getRealName()));
            //身份证脱敏
            if (org.apache.commons.lang.StringUtils.isNotBlank(userDOPage.getIdCardNo())) {
                vo.setCardNo(userDOPage.getIdCardNo().replaceAll("(\\d)\\d{16}(\\w)", "$1****************$2"));
            }
            Map<String, Object> idCardImg = userDOPage.getIdCardImg();
            vo.setFrontUrl((String) idCardImg.get("front"));
            vo.setBackUrl((String) idCardImg.get("back"));
            return Wrapper.success(vo);
        }
        return Wrapper.success();
    }

    /**
     * 账户安全-实名验证-上传身份证信息
     *
     * @return 操作结果
     */
    @Override
    public Wrapper<UserAccountAuthQueryVO> uploadIdCard(UserUploadIdCardVO userUploadIdCardVO) {
        //1.先从redis中获取assess_token
        MemberAuthTypeConfigDO memberAuthTypeConfigDO = memberAuthTypeConfigFeignService.findEnableAuthConfig();
        HashMap<String, Object> config = memberAuthTypeConfigDO.getConfig();
        String apiKey = (String) config.get(BaiDuConfigEnum.API_KEY.getCode());
        String secretKey = (String) config.get(BaiDuConfigEnum.SECRET_KEY.getCode());
        String aesKey = (String) config.get(BaiDuConfigEnum.AES_KEY.getCode());
        if (!StringUtils.hasLength(apiKey) || !StringUtils.hasLength(secretKey) || !StringUtils.hasLength(aesKey)) {
            return Wrapper.fail(ResponseCode.MC_MS_CONFIGURE_AUTH_INFO_FIRST);
        }
        //切割数据
        apiKey = apiKey.substring(0, apiKey.indexOf("|"));
        secretKey = secretKey.substring(0, secretKey.indexOf("|"));
        aesKey = aesKey.substring(0, aesKey.indexOf("|"));
        String assessToken = authUtil.getAuth(apiKey, secretKey);
        String frontResult;
        //2.上传正面图片信息
        try {
            frontResult = IdCardUtil.idCard(userUploadIdCardVO.getFrontUrl(), aesKey, assessToken);
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.MC_MS_INCORRECT_CONFIGURATION);
        }
        //3.解析返回结果
        JSONObject frontResp = JSONObject.parseObject(frontResult);
        String frontWordsResult = frontResp.getString("words_result");
        JSONObject attributes = JSONObject.parseObject(frontWordsResult);
        String nameKey = attributes.getString("姓名");
        String cardNoKey = attributes.getString("公民身份号码");
        String addressKey = attributes.getString("住址");
        if (!StringUtils.hasLength(nameKey) || !StringUtils.hasLength(cardNoKey) || !StringUtils.hasLength(addressKey)) {
            return Wrapper.fail(ResponseCode.MC_MS_UPLOAD_REALLY_FRONT_URL);
        }
        JSONObject nameResp = JSONObject.parseObject(nameKey);
        JSONObject cardNoResp = JSONObject.parseObject(cardNoKey);
        JSONObject addressResp = JSONObject.parseObject(addressKey);
        String name = nameResp.getString("words");
        String cardNo = cardNoResp.getString("words");
        String address = addressResp.getString("words");
        if (!StringUtils.hasLength(name) || !StringUtils.hasLength(cardNo) || !StringUtils.hasLength(address)) {
            return Wrapper.fail(ResponseCode.MC_MS_REAL_NAME_VERIFICATION_FAILED);
        }
        //4.上传背面图片信息
        String backResult;
        try {
            backResult = IdCardUtil.idCard(userUploadIdCardVO.getBackUrl(), aesKey, assessToken);
        } catch (Exception e) {
            return Wrapper.fail(ResponseCode.MC_MS_INCORRECT_CONFIGURATION);
        }
        JSONObject backResp = JSONObject.parseObject(backResult);
        String backWordsResult = backResp.getString("words_result");
        JSONObject backAttributes = JSONObject.parseObject(backWordsResult);
        String expirationDate = backAttributes.getString("失效日期");
        String dateOfIssue = backAttributes.getString("签发日期");
        String issuingAuthority = backAttributes.getString("签发机关");
        if (!StringUtils.hasLength(expirationDate) || !StringUtils.hasLength(dateOfIssue) || !StringUtils.hasLength(issuingAuthority)) {
            return Wrapper.fail(ResponseCode.MC_MS_UPLOAD_REALLY_BACK_URL);
        }

        JSONObject expirationResp = JSONObject.parseObject(expirationDate);
        JSONObject dateOfIssueResp = JSONObject.parseObject(dateOfIssue);
        JSONObject issuingAuthorityResp = JSONObject.parseObject(issuingAuthority);
        Long expirationR = expirationResp.getLong("words");
        Long dateOfIssueR = dateOfIssueResp.getLong("words");
        String issuingAuthorityR = issuingAuthorityResp.getString("words");
        long localDateTime = Long.parseLong(DateUtil.formatLocalDateTime());//当前日期
        if (localDateTime <= dateOfIssueR || localDateTime >= expirationR) {
            return Wrapper.fail(ResponseCode.MC_MS_ID_CARD_DATA_INVALID);
        }
        String substring = issuingAuthorityR.substring(0, issuingAuthorityR.length() - 3);//XXX公安局
        if (!address.contains(substring)) {
            return Wrapper.fail(ResponseCode.MC_MS_UPLOAD_REALLY_BACK_URL);
        }
        UserAccountAuthQueryVO vo = new UserAccountAuthQueryVO();
        vo.setName(name);
        vo.setCardNo(cardNo);
        return Wrapper.success(vo);
    }

    /**
     * 账户安全-实名验证-保存身份证信息
     *
     * @param headers        Http头部信息
     * @param userAuthInfoVO 实名信息请求体
     * @return 操作结果
     */
    @Override
    public Wrapper<Void> saveAuthInfo(HttpHeaders headers, UserAuthInfoVO userAuthInfoVO) {
        UserLoginCacheDTO loginUser = memberCacheService.checkUserFromCache(headers);
        MemberUserDO userDO = memberUserRepository.findById(loginUser.getUserId()).orElse(null);
        if (userDO == null) {
            return Wrapper.fail(ResponseCode.MC_MS_MEMBER_USER_DOES_NOT_EXIST);
        }
        userDO.setRealName(userAuthInfoVO.getName());
        userDO.setIdCardNo(userAuthInfoVO.getCardNo());
        Map<String, Object> map = new HashMap<>();
        map.put("front", userAuthInfoVO.getFrontUrl());
        map.put("back", userAuthInfoVO.getBackUrl());
        userDO.setIdCardImg(map);
        userDO.setIsAuth(2);//已实名验证
        memberUserRepository.saveAndFlush(userDO);
        return Wrapper.success();
    }
}
